﻿using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Configuration;
using System.Data;
using System.Data.SqlClient;
using System.Xml;
using System.IO;
using TSL_Tools.SqlTools;


namespace ReportingEngine
{
    public partial class TSL_ReportingEngine
    {
        /// <summary>
        /// Calculates the list of starting and ending times for intervals in the load test where the user count remained constant. 
        /// It uses the minimum time and points configured in the user application settings to determine a safe minimum interval amount.
        /// </summary>
        /// <param name="intervals"> The integer array stores values in the following order: FinalBeginningInterval, FinalEndingInterval, CurrentUserCount, MinDataPointCounter</param>
        /// <param name="runId"></param>
        /// <returns></returns>
        public TimeSpan GetConstantLoadIntervals(out List<int[]> intervals, int runId)
        {
            intervals = new List<int[]>();

            DateTime dt = DateTime.Now;

            int minimumDataPointsForInterval = minimumPointsForConstantInterval;
            int minimumSecondsForInterval = minimumSecondsForConstantInterval;

            string sqlCmd = String.Format(TSL_ReportingEngine.Sql_USERLOADPROFILE, runId);
            DataTable table;
            tts.ExecuteReaderTable(sqlCmd, out table);
            mostRecentSqlQuery = sqlCmd;

            // These implement the rules of: a) mimimum seconds to be considered a constant rate and b) minimum # of samples to be considered a constant rate.

            /// The user count value at the beginning of a possible series.
            int BeginningUserCount = 0;

            /// This count starts == BeginningUserCount but is updated every iteration of the loop.
            int CurrentUserCount = 0;

            /// This is the value that will be entered into the List. It is the user count during the last sample in the interval.
            int FinalUserCount = 0;

            /// This is the value that will be entered into the List. It is the final beginning time value.
            int FinalBeginningInterval = 0;

            /// The time value at the beginning of a possible series.
            int BeginningInterval = 0;

            /// This count starts == BeginningInterval but is updated every iteration of the loop.
            int CurrentInterval = 0;

            /// This is the value that will be entered into the List. It is the final time value for the current interval.
            /// This value is compared to the user-supplied value for the minimum number of seconds required to count as a step.
            int FinalEndingInterval = 0;

            /// This counts the number of consecutive elements have the same user count value. This is compared to the user-supplied value.
            int MinDataPointCounter = 1;

            /// Remove those that don't meet the minimum data point or minimum constant seconds criteria.
            foreach (DataRow row in table.Rows)
            {
                /// Set the initial user count and interval values from to those read from the database.
                CurrentUserCount = Convert.ToInt32(row.ItemArray[0]);
                CurrentInterval = (int)row.ItemArray[1];

                /// When MinDataPointCounter or MinSecondsCounter = 0, store the user count for comparison later.
                if (MinDataPointCounter == 1)
                {
                    /// Since MinDataPointCounter == 1, this is potentially the first of a new series.

                    /// At this point, the potential beginning and end values are the same.
                    FinalBeginningInterval = BeginningInterval;
                }

                /// If the current user count = the current interval user count, this value is part of the same interval.
                if (BeginningUserCount == CurrentUserCount)
                {
                    /// Increment the data point counter and update CarrOverInterval to the current value.
                    MinDataPointCounter++;
                    FinalEndingInterval = CurrentInterval;
                    FinalUserCount = CurrentUserCount;
                }
                else
                {
                    /// The value is no longer the same.
                    /// This may be the beginning of a new interval and the prior element was the last of the prior one.

                    /// If the minimm number of data points needed to qualify has been reached or exceeded, enter the values into the list.
                    if (MinDataPointCounter >= minimumDataPointsForInterval && CurrentInterval >= minimumSecondsForInterval)
                    {
                        /// The minimum has been met or exceeded.
                        /// Enter the beginning value, ending value, the user count, and the number of samples for the interval.
                        intervals.Add(new int[] { FinalBeginningInterval, FinalEndingInterval, FinalUserCount, MinDataPointCounter });
                    }

                    /// The minimum was not met. Do not add the intervals to the list. Reset the interval counter.
                    MinDataPointCounter = 1;

                    /// Since this is a new user value, it is potentially the beginning of a new series. Capture the Interval value and user count.

                    /// Update BeginningInterval to CurrentInterval.
                    BeginningInterval = CurrentInterval;

                    /// Record the current user count.
                    BeginningUserCount = CurrentUserCount;
                }
            }

            /// This catches the possibility that the last several records are a set.
            /// If the current user count = the current interval user count, this value is part of the same interval.
            if (BeginningUserCount == CurrentUserCount)
            {
                /// The value is no longer the same. This is the beginning of a new interval and the prior element was the last of the prior one.
                if (MinDataPointCounter >= minimumDataPointsForInterval)
                {
                    /// The minimum has been met or exceeded.
                    /// Enter the beginning value, ending value, the user count, and the number of samples for the interval.
                    intervals.Add(new int[] { FinalBeginningInterval, FinalEndingInterval, CurrentUserCount, MinDataPointCounter });
                }
            }
            // [GEOFFGR] -- Added return value
            return (TimeSpan)(DateTime.Now - dt);
        }

        public TimeSpan GetConstantLoadIntervals(ref DataTable intervals, int runId)
        {

            DateTime dt = DateTime.Now;

            int minimumDataPointsForInterval = minimumPointsForConstantInterval;
            int minimumSecondsForInterval = minimumSecondsForConstantInterval;

            string sqlCmd = String.Format(TSL_ReportingEngine.Sql_USERLOADPROFILE, runId);
            DataTable table;
            tts.ExecuteReaderTable(sqlCmd, out table);
            mostRecentSqlQuery = sqlCmd;

            // These implement the rules of: a) mimimum seconds to be considered a constant rate and b) minimum # of samples to be considered a constant rate.

            /// The user count value at the beginning of a possible series.
            int BeginningUserCount = 0;

            /// This count starts == BeginningUserCount but is updated every iteration of the loop.
            int CurrentUserCount = 0;

            /// This is the value that will be entered into the List. It is the user count during the last sample in the interval.
            int FinalUserCount = 0;

            /// This is the value that will be entered into the List. It is the final beginning time value.
            int FinalBeginningInterval = 0;

            /// The time value at the beginning of a possible series.
            int BeginningInterval = 0;

            /// This count starts == BeginningInterval but is updated every iteration of the loop.
            int CurrentInterval = 0;

            /// This is the value that will be entered into the List. It is the final time value for the current interval.
            /// This value is compared to the user-supplied value for the minimum number of seconds required to count as a step.
            int FinalEndingInterval = 0;

            /// This counts the number of consecutive elements have the same user count value. This is compared to the user-supplied value.
            int MinDataPointCounter = 1;

            /// Remove those that don't meet the minimum data point or minimum constant seconds criteria.
            foreach (DataRow row in table.Rows)
            {
                /// Set the initial user count and interval values from to those read from the database.
                CurrentUserCount = Convert.ToInt32(row.ItemArray[0]);
                CurrentInterval = (int)row.ItemArray[1];

                /// When MinDataPointCounter or MinSecondsCounter = 0, store the user count for comparison later.
                if (MinDataPointCounter == 1)
                {
                    /// Since MinDataPointCounter == 1, this is potentially the first of a new series.

                    /// At this point, the potential beginning and end values are the same.
                    FinalBeginningInterval = BeginningInterval;
                }

                /// If the current user count = the current interval user count, this value is part of the same interval.
                if (BeginningUserCount == CurrentUserCount)
                {
                    /// Increment the data point counter and update CarrOverInterval to the current value.
                    MinDataPointCounter++;
                    FinalEndingInterval = CurrentInterval;
                    FinalUserCount = CurrentUserCount;
                }
                else
                {
                    /// The value is no longer the same.
                    /// This may be the beginning of a new interval and the prior element was the last of the prior one.

                    /// If the minimm number of data points needed to qualify has been reached or exceeded, enter the values into the list.
                    if (MinDataPointCounter >= minimumDataPointsForInterval && CurrentInterval >= minimumSecondsForInterval)
                    {
                        /// The minimum has been met or exceeded.
                        /// Enter the beginning value, ending value, the user count, and the number of samples for the interval.
                        //intervals.Add(new int[] { FinalBeginningInterval, FinalEndingInterval, FinalUserCount, MinDataPointCounter });
                        intervals.Rows.Add(runId, FinalBeginningInterval, FinalEndingInterval, FinalUserCount, MinDataPointCounter);
                    }

                    /// The minimum was not met. Do not add the intervals to the list. Reset the interval counter.
                    MinDataPointCounter = 1;

                    /// Since this is a new user value, it is potentially the beginning of a new series. Capture the Interval value and user count.

                    /// Update BeginningInterval to CurrentInterval.
                    BeginningInterval = CurrentInterval;

                    /// Record the current user count.
                    BeginningUserCount = CurrentUserCount;
                }
            }

            /// This catches the possibility that the last several records are a set.
            /// If the current user count = the current interval user count, this value is part of the same interval.
            if (BeginningUserCount == CurrentUserCount)
            {
                /// The value is no longer the same. This is the beginning of a new interval and the prior element was the last of the prior one.
                if (MinDataPointCounter >= minimumDataPointsForInterval)
                {
                    /// The minimum has been met or exceeded.
                    /// Enter the beginning value, ending value, the user count, and the number of samples for the interval.
                    intervals.Rows.Add(runId, FinalBeginningInterval, FinalEndingInterval, FinalUserCount, MinDataPointCounter);
                }
            }
            // [GEOFFGR] -- Added return value
            return (TimeSpan)(DateTime.Now - dt);
        }

        public string AddConstantLoadIntervals()
        {
            DateTime dt = DateTime.Now;
            List<int> runs = new List<int>();
            // Get List of runs already processed
            tts.ExecuteReaderIntList(@"
SELECT LoadTestRunId FROM TSL_LoadTestCoreInfo 
WHERE FLAG_ContainsStepLoadProfile = 1 AND
	LoadTestRunId NOT IN (SELECT DISTINCT LoadTestRunId FROM TSL_LoadTestIntervals)", out runs, -1);
            
            // No runs need to be updated
            if(runs.Count == 0)
            {
                return "No Data Added from ConstantIntervals";
            }

            DataTable intervals = new DataTable();
            intervals.Columns.Add("LoadTestRunId", System.Type.GetType("System.Int32"));
            intervals.Columns.Add("StartOffset", System.Type.GetType("System.Int32"));
            intervals.Columns.Add("EndOffset", System.Type.GetType("System.Int32"));
            intervals.Columns.Add("UserLoad", System.Type.GetType("System.Int32"));
            intervals.Columns.Add("NumberOfDataPoints", System.Type.GetType("System.Int32"));

            for (int x = 0; x < runs.Count; x++)
            {
                if (runs[x] != -1)
                {
                    GetConstantLoadIntervals(ref intervals, runs[x]);
                }
            }
            TimeSpan ts = (TimeSpan)(DateTime.Now - dt);

            string str;
            TimeSpan ts2 = tts.ExecuteSqlBulkCopy("TSL_LoadTestIntervals", intervals, out str);
            return String.Format("{0} seconds getting data and {1} seconds writing data", ts.TotalSeconds, ts2.TotalSeconds);
        }
    }
}
